package com.hotspot.chartview.view;

import java.util.ArrayList;
import java.util.List;

import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.Align;
import android.graphics.Paint.FontMetricsInt;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;

import com.hotspot.chartview.R;
import com.hotspot.chartview.model.LineChartData;

/**
 * 自定义线性图
 * 
 * @author BaiYuliang
 * 
 */
public class LineChart extends View implements AnimatorUpdateListener {

    /**
     * 从xml中读取对应的参数
     */
    private int mBgColor; // 背景色
    private int mCellWidth; // 单元格的宽度
    private int mCellHeight; // 单元格的高度
    private boolean mIsPointSolid; // 点是否是实心
    private int mPointRadius; // 点的半径
    private int mPointColor; // 点的颜色
    private int mCheckedPointColor; // 选中项点的颜色
    private int mLineColor; // 连线颜色
    private int mDividerColor; // 底部分割线颜色
    private int mTextColor; // 字体颜色
    private int mCheckedTextColor; // 选中项字体颜色
    private int mTextSize; // 字体大小

    /**
     * 画笔
     */
    private Paint mPaintPoint; // 画点用的画笔
    private Paint mPaintCheckedPoint; // 画选中项点用的画笔
    private Paint mPaintFillPoint; // 填充点用的画笔
    private Paint mPaintLine; // 画线用的画笔
    private Paint mPaintDivider; // 画底部分割线用的画笔
    private Paint mPaintText; // 画文字用的画笔
    private Paint mPaintCheckedText; // 画选中项文字用的画笔

    private boolean mSubtitleEnable = true; // 二级标题是否显示
    private List<LineChartData> mLineChartDatas; // 报表数据
    private int mPointViewHeight; // 报表的高度
    private float mDataMaxHeight; // 数据的最大值
    private int mDeltaX;
    private int mDeltaY;
    private int mCheckedItemIndex = -1; // 选中项的索引

    /**
     * 动画
     */
    private float mPhaseX = 1f;
    private float mPhaseY = 1f;
    private ObjectAnimator mAnimatorX;
    private ObjectAnimator mAnimatorY;

    public LineChart(Context context) {
        this(context, null, 0);
    }

    public LineChart(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public LineChart(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        if (attrs != null) {
            Resources resources = getResources();
            TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.LineChart);
            mBgColor = typedArray.getColor(R.styleable.LineChart_bg_color,
                    resources.getColor(R.color.line_chart_bg_color_default));
            mCellWidth = typedArray.getDimensionPixelSize(R.styleable.LineChart_cell_width, 0);
            mCellHeight = typedArray.getDimensionPixelSize(R.styleable.LineChart_cell_height, 0);
            mIsPointSolid = typedArray.getBoolean(R.styleable.LineChart_point_solid, true);
            mPointRadius = typedArray.getDimensionPixelSize(R.styleable.LineChart_point_radius, 9);
            mPointColor = typedArray.getColor(R.styleable.LineChart_point_color,
                    resources.getColor(R.color.line_chart_point_color_default));
            mCheckedPointColor = typedArray.getColor(R.styleable.LineChart_checked_point_color,
                    resources.getColor(R.color.line_chart_checked_point_color_default));
            mLineColor = typedArray.getColor(R.styleable.LineChart_line_color,
                    resources.getColor(R.color.line_chart_line_color_default));
            mDividerColor = typedArray.getColor(R.styleable.LineChart_divider_color,
                    resources.getColor(R.color.line_chart_divider_color_default));
            mTextColor = typedArray.getColor(R.styleable.LineChart_text_color,
                    resources.getColor(R.color.line_chart_text_color_default));
            mCheckedTextColor = typedArray.getColor(R.styleable.LineChart_checked_text_color,
                    resources.getColor(R.color.line_chart_checked_text_color_default));
            mTextSize = typedArray.getDimensionPixelSize(R.styleable.LineChart_text_size, 27);
            typedArray.recycle();
        }

        init(context); // 初始化一些参数
    }

    /**
     * 初始化一些参数
     * 
     * @param context
     *            上下文
     */
    private void init(Context context) {
        mLineChartDatas = new ArrayList<LineChartData>();

        /**
         * 创建画点用的画笔
         */
        mPaintPoint = new Paint();
        mPaintPoint.setColor(mPointColor);
        if (mIsPointSolid) {
            mPaintPoint.setStyle(Paint.Style.FILL_AND_STROKE);
        } else {
            mPaintPoint.setStyle(Paint.Style.STROKE);
        }
        mPaintPoint.setStrokeWidth(3);
        mPaintPoint.setAntiAlias(true);

        /**
         * 创建画最后点用的画笔
         */
        mPaintCheckedPoint = new Paint();
        mPaintCheckedPoint.setColor(mCheckedPointColor);
        if (mIsPointSolid) {
            mPaintCheckedPoint.setStyle(Paint.Style.FILL_AND_STROKE);
        } else {
            mPaintCheckedPoint.setStyle(Paint.Style.STROKE);
        }
        mPaintCheckedPoint.setStrokeWidth(3);
        mPaintCheckedPoint.setAntiAlias(true);

        /**
         * 填充点用的画笔
         */
        mPaintFillPoint = new Paint();
        mPaintFillPoint.setColor(mBgColor);
        mPaintFillPoint.setStyle(Paint.Style.FILL);
        mPaintFillPoint.setAntiAlias(true);

        /**
         * 创建画线用的画笔
         */
        mPaintLine = new Paint();
        mPaintLine.setColor(mLineColor);
        mPaintLine.setStyle(Paint.Style.FILL);
        mPaintLine.setStrokeWidth(3);
        mPaintLine.setAntiAlias(true);

        /**
         * 创建画底部分割线用的画笔
         */
        mPaintDivider = new Paint();
        mPaintDivider.setColor(mDividerColor);
        mPaintDivider.setStrokeWidth(1);
        mPaintDivider.setAntiAlias(true);

        /**
         * 创建画文字用的画笔
         */
        mPaintText = new Paint();
        mPaintText.setColor(mTextColor);
        mPaintText.setTextSize(mTextSize);
        mPaintText.setTextAlign(Align.CENTER);
        mPaintText.setAntiAlias(true);

        /**
         * 创建画最后一个文字用的画笔
         */
        mPaintCheckedText = new Paint();
        mPaintCheckedText.setColor(mCheckedTextColor);
        mPaintCheckedText.setTextSize(mTextSize);
        mPaintCheckedText.setTextAlign(Align.CENTER);
        mPaintCheckedText.setAntiAlias(true);
    }

    /**
     * 初始化单元格的大小和位置
     */
    private void initCellSizeAndPosition() {
        if (mLineChartDatas.size() == 0) {
            return;
        }
        int width = getMeasuredWidth();
        int height = getMeasuredHeight();
        if (mCellWidth == 0) {
            mCellWidth = width / mLineChartDatas.size();
        }
        if (mCellHeight == 0) {
            mCellHeight = height / mLineChartDatas.size();
        }

        mPointViewHeight = (int) (height * 0.6); // 折线图部分占View的6/10
        mDeltaX = mCellWidth / 2;
        mDeltaY = mPointRadius * 2;

        /**
         * 内容的最大值
         */
        mDataMaxHeight = 0;
        for (LineChartData lineChartData : mLineChartDatas) {
            if (lineChartData.height >= mDataMaxHeight) {
                mDataMaxHeight = lineChartData.height;
            }
        }

        /**
         * 当所有的数据都为0的情况
         */
        if (mDataMaxHeight == 0) {
            mDataMaxHeight = mPointViewHeight;
        }
    }

    /**
     * 画点
     * 
     * @param canvas
     *            画布
     */
    private void drawPoints(Canvas canvas) {
        canvas.save();
        canvas.translate(mDeltaX, mDeltaY);
        float pointX = 0;
        float radius = mPointRadius - mPaintPoint.getStrokeWidth();
        for (int i = 0; i < mLineChartDatas.size(); i++) {
            LineChartData lineChartData = mLineChartDatas.get(i);
            float pointY = mPointViewHeight * (1 - mPhaseY * lineChartData.height / mDataMaxHeight);
            if (i == mCheckedItemIndex) {
                canvas.drawCircle(pointX, pointY, radius, mPaintCheckedPoint);
                if (!mIsPointSolid) {
                    canvas.drawCircle(pointX, pointY, radius, mPaintFillPoint);
                }
            } else {
                canvas.drawCircle(pointX, pointY, radius, mPaintPoint);
                if (!mIsPointSolid) {
                    canvas.drawCircle(pointX, pointY, radius, mPaintFillPoint);
                }
            }
            pointX += mCellWidth;
        }
        canvas.restore();
    }

    /**
     * 画线
     * 
     * @param canvas
     *            画布
     */
    private void drawLines(Canvas canvas) {
        canvas.save();
        canvas.translate(mDeltaX, mDeltaY);
        float pointX = 0;
        for (int i = 0; i < mLineChartDatas.size() - 1; i++) {
            LineChartData startPoint = mLineChartDatas.get(i); // 起点
            LineChartData endPoint = mLineChartDatas.get(i + 1); // 终点
            float startY = mPointViewHeight * (1 - mPhaseY * startPoint.height / mDataMaxHeight);
            float endY = mPointViewHeight * (1 - mPhaseY * endPoint.height / mDataMaxHeight);
            canvas.drawLine(pointX, startY, pointX + mCellWidth, endY, mPaintLine);
            pointX += mCellWidth;
        }
        canvas.restore();
    }

    /**
     * 画文字
     * 
     * @param canvas
     *            画布
     */
    private void drawBottomText(Canvas canvas) {
        canvas.save();
        canvas.translate(0, mPointViewHeight + mDeltaY + mPointRadius);
        canvas.drawLine(0, 0, getMeasuredWidth(), 0, mPaintDivider);

        /**
         * 画一级标题
         */
        int titleLeft = 0;
        int titleTop = 10;
        int titleBottom = titleTop + (int) mPaintText.getTextSize() + 10;
        for (int i = 0; i < mLineChartDatas.size(); i++) {
            LineChartData lineChartData = mLineChartDatas.get(i);
            Rect targetRect = new Rect(titleLeft, titleTop, titleLeft + mCellWidth, titleBottom);
            FontMetricsInt fontMetrics = mPaintText.getFontMetricsInt();
            int baseLine = targetRect.top
                    + (targetRect.bottom - targetRect.top - fontMetrics.bottom + fontMetrics.top)
                    / 2 - fontMetrics.top;
            if (i == mCheckedItemIndex) {
                canvas.drawText(lineChartData.title, targetRect.centerX(), baseLine,
                        mPaintCheckedText);
            } else {
                canvas.drawText(lineChartData.title, targetRect.centerX(), baseLine, mPaintText);
            }
            titleLeft += mCellWidth;
        }

        /**
         * 画二级标题
         */
        int subtitleLeft = 0;
        int subtitleTop = titleBottom;
        int subtitleBottom = subtitleTop + (int) mPaintText.getTextSize() + 10;
        if (mSubtitleEnable) {
            for (int i = 0; i < mLineChartDatas.size(); i++) {
                LineChartData lineChartData = mLineChartDatas.get(i);
                Rect targetRect = new Rect(subtitleLeft, subtitleTop, subtitleLeft + mCellWidth,
                        subtitleBottom);
                FontMetricsInt fontMetrics = mPaintText.getFontMetricsInt();
                int baseLine = targetRect.top
                        + (targetRect.bottom - targetRect.top - fontMetrics.bottom + fontMetrics.top)
                        / 2 - fontMetrics.top;
                if (i == mCheckedItemIndex) {
                    canvas.drawText(lineChartData.subtitle, targetRect.centerX(), baseLine,
                            mPaintCheckedText);
                } else {
                    canvas.drawText(lineChartData.subtitle, targetRect.centerX(), baseLine,
                            mPaintText);
                }
                subtitleLeft += mCellWidth;
            }
        }
        canvas.restore();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        initCellSizeAndPosition(); // 初始化单元格大小和初始位置
    }

    @Override
    protected void onDraw(Canvas canvas) {
        drawLines(canvas); // 画线
        drawPoints(canvas); // 画点
        drawBottomText(canvas); // 画底部文字
    }

    @Override
    public void onAnimationUpdate(ValueAnimator valueAnimator) {
        invalidate();
    }

    /**
     * phaseX的setter方法，与ObjectAnimator配合使用
     * 
     * @param phaseX
     *            X轴动画完执行进度
     */
    public void setPhaseX(float phaseX) {
        mPhaseX = phaseX;
    }

    /**
     * phaseY的setter方法，与ObjectAnimator配合使用
     * 
     * @param phaseY
     *            Y轴动画执行进度
     */
    public void setPhaseY(float phaseY) {
        mPhaseY = phaseY;
    }

    /**
     * X轴执行动画
     * 
     * @param durationMillis
     *            执行动画的时间
     */
    public void animateX(int durationMillis) {
        mAnimatorX = ObjectAnimator.ofFloat(this, "phaseX", 0f, 1f);
        mAnimatorX.setDuration(durationMillis);
        mAnimatorX.addUpdateListener(this);
        mAnimatorX.start();
    }

    /**
     * Y轴执行动画
     * 
     * @param durationMillis
     *            执行动画的时间
     */
    public void animateY(int durationMillis) {
        mAnimatorY = ObjectAnimator.ofFloat(this, "phaseY", 0f, 1f);
        mAnimatorY.setDuration(durationMillis);
        mAnimatorY.addUpdateListener(this);
        mAnimatorY.start();
    }

    /**
     * 设置是否显示二级标题
     * 
     * @param subtitleEnable
     *            true:显示二级标题；false:不显示二级标题
     */
    public void setSubtitleEnable(boolean subtitleEnable) {
        mSubtitleEnable = subtitleEnable;
    }

    /**
     * 设置要显示
     * 
     * @param lineChartDatas
     *            报表内容
     */
    public void setLineChartData(List<LineChartData> lineChartDatas) {
        mLineChartDatas.clear();
        if (lineChartDatas != null && lineChartDatas.size() > 0) {
            mLineChartDatas.addAll(lineChartDatas);
        }
        initCellSizeAndPosition();
        invalidate();
    }

    /**
     * 设置选中项
     * 
     * @param index
     *            选中项索引
     */
    public void setCheckedItemIndex(int index) {
        mCheckedItemIndex = index;
    }

}
